#!/usr/bin/env python

import sys
import re
from itertools import izip_longest
from collections import Counter
import argparse

def parse_range(astr):
    result = set()
    for part in astr.split(','):
        x = part.split('-')
        result.update(range(int(x[0]), int(x[-1]) + 1))
    return sorted(result)


def sortby(x):
   return x.split(':')[0]

def main():

   if len(sys.argv) == 5:

      cyclerange = parse_range(sys.argv[4])

      cycletostartcheckingfrom = cyclerange[0] + 1;
      sys.stderr.write('cycletostartcheckingfrom=%d\n' % cycletostartcheckingfrom)


      addrshelper = []
      addrs = []
      cycle = 0
      allow = False

      master = []

      addrs_from_cycle = []

      ms = []

      f = open(sys.argv[1])

      for line in f:

         if line.startswith('DSC'):

            if re.search(sys.argv[2], line):

               if addrs:
                  master.append(addrs)

               addrshelper = []
               addrs = []
               cycle += 1

               allow = True

            elif re.search(sys.argv[3], line):
               allow = False


            if cycle >= cycletostartcheckingfrom:

               # build the list with all future malloc and realloc addresses
               #if ',=' in line:
               if 'm,=' in line or 'r,=' in line:

                  result = int(line.split(',=')[1].split(',')[0], 16)
                  if result not in addrs_from_cycle:
                     addrs_from_cycle.append(result)

               # build the list with all future malloc and realloc ranges
               if 'm,=' in line or 'r,=' in line:

                  result = re.findall(r'=[0-9a-f]+', line)

                  m = int(result[0][1:], 16)
                  s = int(result[2][1:])
                  ms.append((m, m + s, cycle))

            if allow:

               if cycle in cyclerange:

                  #if 'QImageData::create()' in line :
                  #if not 'QImageData::create()' in line and not '~QImageData()' in line:
                  #if 'libv3d' in line :
                  #if 'QImageData::create()' in line or '~QImageData()' in line or 'libv3d' in line:
                  #if 'libjpeg:alloc_large' in line:
                  #if 'ListData' in line :

                  #if 'QImageData::create()' in line or 'QImageData::create2()' in line or '~QImageData()' in line:
                  #if 'QImageData::create2()' in line:
                  #if 'QImageData::create()' in line:
                  #if 'QImageData::create()' in line or 'm,=' in line or 'r,=' in line:
                  if 'QImageData::create()' in line or '~QImageData()_free' in line:

                     addrresult = re.search(r',=[0-9a-f]+', line)

                     if addrresult:

                        addr = int(addrresult.group()[2:], 16)

                        if addr not in addrshelper:

                           addrshelper.append(addr)
                           addrs.append([])
                           addrs[addrshelper.index(addr)].append(cycle)
                           addrs[addrshelper.index(addr)].append(str('0x%08x') %addr)

                        #addrs[addrshelper.index(addr)].append((line.split('::')[1])[:2])

                        item = (line.split(' ')[3])
                        #print 'item=', item

                        #libQt5Core:QString::reallocData(unsigned_in:r,=b41930,ra=7411a664,sz=64
                        #libQt5Gui:QImage::~QImage():QImageData::~QImageData(),=f26340,ra=7463e1b4,sz=0
                        #libQt5Gui:QImage::QImage(in:QImageData::create(),=e46c40,ra=7463e748,sz=100,5x20@32


                        if 'QImageData::create()' in item:
                           result = str('c(%s)' %item.split(',')[4])
                           addrs[addrshelper.index(addr)].append(result)

                        elif '~QImageData()_free' in item:
                           result = '~free()'
                           addrs[addrshelper.index(addr)].append(result)

                        elif 'QImageData::create2()' in item:
                           result = str('c2(%s)' %item.split(',')[4])
                           addrs[addrshelper.index(addr)].append(result)

                        elif '~QImageData()_nofree' in item:
                           result = '~nofree()'
                           addrs[addrshelper.index(addr)].append(result)

                        elif 'm,=' in item:
                           result = str('m(%s)' %item.split('sz=')[1][:-1])
                           addrs[addrshelper.index(addr)].append(result)

                        elif 'r,=' in item:
                           result = str('r(%s)' %item.split('sz=')[1][:-1])
                           addrs[addrshelper.index(addr)].append(result)

                        else:
                           result = str('?')
                           addrs[addrshelper.index(addr)].append(result)
                        

      f.close()

      #for addr in addrs:
      #   print addr[0],
      #   print addr[1],
      #   print Counter(addr[1:]).items()


      final = []
      final_addronly = []

      for item in master:
         final.append([])
         final_addronly.append([])

         for a in item:
            #res = str(a[0]) + ':' + str(a[1]) + ':' + repr(Counter(a[2:]).items()).replace(', ',':')
            res = str(a[1]) + ':' + repr(Counter(a[2:]).items()).replace(', ',':')
            res_addronly = str(a[1])
            #print res
            final[master.index(item)].append(res)
            final_addronly[master.index(item)].append(res_addronly)

         final[master.index(item)].sort(key = sortby)
         final_addronly[master.index(item)].sort()





      if (0):
         for row in izip_longest(*final):
            print row

      else:
         final_union = sorted(set().union(*final))
         final_addronly_union = sorted(set().union(*final_addronly))
         #for item in final_union:
         #   print item
         new_lists = [[x if x in my_list else "----------" for x in final_addronly_union] for my_list in final_addronly]
         i = 0
         j = 0
         for row in izip_longest(*new_lists):
            #print i, row
            mylist = row
            if mylist[0] == '----------':
               print '----------',
            else:

               future_addrs = False
               future_ranges = False

               if int(mylist[0], 16) in addrs_from_cycle:
                  future_addrs = True
               else:
                  future_addrs = False

               #if 'nofree' in final[0][i]:
               if (1):
                  #check in ranges
                  for ms_item in ms:
                     if int(mylist[0], 16) >= ms_item[0] and int(mylist[0], 16) < ms_item[1]:
                        future_ranges = True
                        break

               #
               print mylist[0], final[0][i],

               if future_addrs:
                  print '***',
               if future_ranges:
                  print '+++',

               #sys.stderr.write('%s' %(final[0][i]))
               #if future_addrs:
               #   sys.stderr.write('fa');
               #else:
               #   sys.stderr.write('nofa');
               #if future_ranges:
               #   sys.stderr.write('fr');
               #else:
               #   sys.stderr.write('nofr');
               #sys.stderr.write('\n');

               if not future_ranges:
                  sys.stderr.write('%4d %4d %s\n' %(i, j, final[0][i]))
                  j+= 1

            i+= 1

            print ',', row


   else:
      sys.stderr.write("Usage: %s tdifile cyclepattern-start cyclepattern-end cyclerange cycletostartcheckingfrom\n" % sys.argv[0])

if __name__ == "__main__":
   main()